# 获取流动性（成交额）前200的股票

# 获取流动性前2的板块

# 获取成交量在日线级别横盘缩量的股票

# 获取30、60分钟级别放量的股票
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 假设使用akshare，你需要安装：pip install akshare
import akshare as ak

# 参数定义 - 你需要根据历史回测优化这些值
LIQUIDITY_TOP_N = 200
SECTOR_TOP_N = 2
VOLUME_SHRINK_RATIO = 0.8  # 缩量阈值，例如成交量低于20日均量80%
VOLUME_EXPAND_RATIO = 2.0  # 放量阈值，例如分钟成交量超过前期均量200%
PRICE_FLUCTUATION_THRESHOLD = 0.02  # 横盘阈值，例如日线价格波动率<2%

def get_liquidity_top_stocks(n=LIQUIDITY_TOP_N):
    """获取成交额前N的股票
        这和我下单时间息息相关，30、60分钟时间点下单。
        需要思考的问题是，我仅仅需要前200成交额的股票，我认为这种全部拿到做数据筛选的操作还是有些愚蠢，先尝试直接使用requests加成交额查询前10页数据
    """
    # 示例：获取A股实时成交额数据
    stock_info = ak.stock_zh_a_spot_em()
    # 按成交额排序，取前N
    top_stocks = stock_info.sort_values(by='成交额', ascending=False).head(n)
    return top_stocks[['代码', '名称', '成交额']]

def get_liquidity_top_sectors(n=SECTOR_TOP_N):
    """获取成交额前N的板块
        这个接口并没有成交额排名，是否有其他指标取代呢？或者是从200只股票中判断出板块的强弱吗？或者是用200只票的所属行业来判断板块的强弱
    """
    # 示例：获取板块成交额数据
    sector_info = ak.stock_board_industry_name_em()
    # 按成交额排序，取前N
    top_sectors = sector_info.sort_values(by='成交额', ascending=False).head(n)
    return top_sectors[['板块代码', '板块名称', '成交额']]

def filter_consolidation_shrinkage(stock_list):
    """从股票列表中筛选日线横盘缩量的股票
        如何表征横盘是需要思考的，20天明显不是我用的指标。5、10、20天的均线向上。是否有获取均线斜率的办法
    """
    filtered_stocks = []
    for stock_code in stock_list['代码']:
        # 获取日线数据（最近20日）
        daily_data = ak.stock_zh_a_hist(symbol=stock_code, period="daily", start_date=(datetime.today() - timedelta(days=30)).strftime('%Y%m%d'))
        if daily_data.empty:
            continue
        # 计算20日成交量均值和价格波动率
        daily_data['volume_ma20'] = daily_data['成交量'].rolling(20).mean()
        daily_data['price_range'] = (daily_data['最高'] - daily_data['最低']) / daily_data['开盘']
        latest = daily_data.iloc[-1]
        # 条件：最新成交量缩量（低于均量80%）且价格横盘（波动率<阈值）
        if latest['成交量'] < latest['volume_ma20'] * VOLUME_SHRINK_RATIO and latest['price_range'] < PRICE_FLUCTUATION_THRESHOLD:
            filtered_stocks.append(stock_code)
    return filtered_stocks

def filter_minute_volume_surge(stock_list):
    """从股票列表中筛选30/60分钟放量的股票
        我现在的放量判断是相比较前几天的30、60分钟级别的放量，而不是均量比较
    """
    filtered_stocks = []
    for stock_code in stock_list:
        # 获取30分钟和60分钟数据（最近5天）
        minute_30 = ak.stock_zh_a_hist_min_em(symbol=stock_code, period='30')
        minute_60 = ak.stock_zh_a_hist_min_em(symbol=stock_code, period='60')
        if minute_30.empty or minute_60.empty:
            continue
        # 计算分钟级成交量均值（例如前期10个周期）
        minute_30['volume_ma10'] = minute_30['成交量'].rolling(10).mean()
        minute_60['volume_ma10'] = minute_60['成交量'].rolling(10).mean()
        latest_30 = minute_30.iloc[-1]
        latest_60 = minute_60.iloc[-1]
        # 条件：最新分钟成交量放量（超过均量200%）
        if latest_30['成交量'] > latest_30['volume_ma10'] * VOLUME_EXPAND_RATIO or \
           latest_60['成交量'] > latest_60['volume_ma10'] * VOLUME_EXPAND_RATIO:
            filtered_stocks.append(stock_code)
    return filtered_stocks

# 主流程
if __name__ == "__main__":
    # 步骤1: 获取流动性前200股票
    top_stocks = get_liquidity_top_stocks()
    print(f"流动性前200股票: {len(top_stocks)} 只")
    
    # 步骤2: 获取流动性前2板块（这里假设板块与股票独立，实际可能需要映射）
    top_sectors = get_liquidity_top_sectors()
    print(f"流动性前2板块: {top_sectors['板块名称'].tolist()}")
    
    # 步骤3: 从top_stocks中筛选日线横盘缩量股票
    consolidation_stocks = filter_consolidation_shrinkage(top_stocks)
    print(f"日线横盘缩量股票: {len(consolidation_stocks)} 只")
    
    # 步骤4: 从consolidation_stocks中筛选分钟放量股票
    final_stocks = filter_minute_volume_surge(consolidation_stocks)
    print(f"最终候选股票: {final_stocks}")
